#pragma semicolon 1 // Force strict semicolon mode.

#include <sourcemod>
#include <sdktools>
#include <tf2_stocks>
#include <tfx>
#include <psycore>
#include <sdkhooks>

#define PLUGIN_NAME              "psyFX - PowerUps (more)"
#define PLUGIN_AUTHOR            "Thrawn"
#define PLUGIN_VERSION           "1.0.0.0"
#define PLUGIN_CONTACT           "http://aaa.einfachonline.net/"

#define SOUND_MIRROR		"vo/demoman_go01.wav"



new g_iEffectNum[8] = {-1,...};
new Handle:g_clientEffectTimer[MAXPLAYERS + 1][2];

new bool:g_bHasMirror[MAXPLAYERS + 1] = {false, ...};


public Plugin:myinfo = {
    name        = PLUGIN_NAME,
    author      = PLUGIN_AUTHOR,
    description = PLUGIN_NAME,
    version     = PLUGIN_VERSION,
    url         = PLUGIN_CONTACT
};

public OnPluginStart() {
	// hook clients already in game
	for (new i = 1; i <= MaxClients; i++)
	{
		if (IsClientInGame(i))
		{
			SDKHook(i, SDKHook_OnTakeDamage, OnTakeDamage);
		}
	}	
}

public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype)
{	
	if(attacker > 0 && attacker != victim && g_bHasMirror[victim]) {
		DealDamage2(attacker,RoundToNearest(damage / 2),victim,DMG_GENERIC,"tf_weapon_sniperrifle");

		decl Float:pos[3];
		GetClientEyePosition(victim, pos);
		pos[2] += 4.0;

		TE_ParticleToClient(attacker, "deflect_fx", pos);		
	}
	
	return Plugin_Continue;
}

public OnMapStart()
{
	PrecacheSound(SOUND_MIRROR, true);	
}

public OnAllPluginsLoaded() {
	if(LibraryExists("psycore")) {
		g_iEffectNum[0] = psyRTD_RegisterEffect(psyRTDEffectType_Good,"Reflective Shield","All damage will be mirrored!", EffectMirrorDamage);
	}		
}

public psyRTD_DisableEffect(client,effectId) {
	for(new i = 0; i < sizeof(g_iEffectNum); i++) {
		if(effectId == g_iEffectNum[i]) {
			if(g_clientEffectTimer[client][0] != INVALID_HANDLE)
				TriggerTimer(g_clientEffectTimer[client][0]);

			if(g_clientEffectTimer[client][1] != INVALID_HANDLE)
				TriggerTimer(g_clientEffectTimer[client][1]);
		}
	}
}



public psyRTDAction:EffectMirrorDamage(client) {
	g_clientEffectTimer[client][0] = CreateTimer(6.0, Timer_Mirror, client);

	g_bHasMirror[client] = true;
	SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);

	EmitSoundClient(SOUND_MIRROR, client);
	return psyRTD_Continue;
}

public Action:Timer_Mirror(Handle:timer, any:client) {
	g_clientEffectTimer[client][0] = INVALID_HANDLE;
	
	SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage);
	g_bHasMirror[client] = false;
	
	if (client && IsClientInGame(client) && !IsClientInKickQueue(client)) {
		psyRTD_EffectIsNowDisabled(client, g_iEffectNum[0]);
	}	
}


DealDamage2(victim,damage,attacker=0,dmg_type=DMG_GENERIC,String:weapon[]="")
{
	if(victim>0 && IsValidEdict(victim) && IsClientInGame(victim) && IsPlayerAlive(victim) && damage>0)
	{
		new String:dmg_str[16];
		IntToString(damage,dmg_str,16);
		new String:dmg_type_str[32];
		IntToString(dmg_type,dmg_type_str,32);
		new pointHurt=CreateEntityByName("point_hurt");
		if(pointHurt)
		{
			DispatchKeyValue(victim,"targetname","war3_hurtme");
			DispatchKeyValue(pointHurt,"DamageTarget","war3_hurtme");
			DispatchKeyValue(pointHurt,"Damage",dmg_str);
			DispatchKeyValue(pointHurt,"DamageType",dmg_type_str);
			if(!StrEqual(weapon,""))
			{
				DispatchKeyValue(pointHurt,"classname",weapon);
			}
			DispatchSpawn(pointHurt);
			
			if(attacker>0) {
				decl Float:pos[3];
				GetClientEyePosition(attacker, pos);				
				
				TeleportEntity(pointHurt, pos, NULL_VECTOR, NULL_VECTOR);
			}
			
			AcceptEntityInput(pointHurt,"Hurt",(attacker>0)?attacker:-1);
			DispatchKeyValue(pointHurt,"classname","point_hurt");
			DispatchKeyValue(victim,"targetname","war3_donthurtme");
			RemoveEdict(pointHurt);
		}
	}
}

TE_ParticleToClient(client,
			String:Name[],
            Float:origin[3]=NULL_VECTOR,
            Float:start[3]=NULL_VECTOR,
            Float:angles[3]=NULL_VECTOR,
            entindex=-1,
            attachtype=-1,
            attachpoint=-1,
            bool:resetParticles=true,
            Float:delay=0.0)
{
    // find string table
    new tblidx = FindStringTable("ParticleEffectNames");
    if (tblidx==INVALID_STRING_TABLE) 
    {
        LogError("Could not find string table: ParticleEffectNames");
        return;
    }
    
    // find particle index
    new String:tmp[256];
    new count = GetStringTableNumStrings(tblidx);
    new stridx = INVALID_STRING_INDEX;
    new i;
    for (i=0; i<count; i++)
    {
        ReadStringTable(tblidx, i, tmp, sizeof(tmp));
        if (StrEqual(tmp, Name, false))
        {
            stridx = i;
            break;
        }
    }
    if (stridx==INVALID_STRING_INDEX)
    {
        LogError("Could not find particle: %s", Name);
        return;
    }
    
    TE_Start("TFParticleEffect");
    TE_WriteFloat("m_vecOrigin[0]", origin[0]);
    TE_WriteFloat("m_vecOrigin[1]", origin[1]);
    TE_WriteFloat("m_vecOrigin[2]", origin[2]);
    TE_WriteFloat("m_vecStart[0]", start[0]);
    TE_WriteFloat("m_vecStart[1]", start[1]);
    TE_WriteFloat("m_vecStart[2]", start[2]);
    TE_WriteVector("m_vecAngles", angles);
    TE_WriteNum("m_iParticleSystemIndex", stridx);
    if (entindex!=-1)
    {
        TE_WriteNum("entindex", entindex);
    }
    if (attachtype!=-1)
    {
        TE_WriteNum("m_iAttachType", attachtype);
    }
    if (attachpoint!=-1)
    {
        TE_WriteNum("m_iAttachmentPointIndex", attachpoint);
    }
    TE_WriteNum("m_bResetParticles", resetParticles ? 1 : 0);    
    TE_SendToClient(client, delay);
}